<?php

namespace App\Models\Product;

use App\Helpers\Code;
use App\Models\BaseModel;
use App\Models\Basic\DictionaryMember;
use Illuminate\Support\Facades\Auth;

class Product extends BaseModel
{

    protected $table = 'products';
    protected $fillable = [
        'parent_id', 'title', 'code', 'test_method', 'price', 'is_urgent', 'is_package', 'is_genetic_disease', 'is_genetic_diagnosis',
        'is_family', 'is_contain_family', 'is_more_monitor', 'is_alone_order', 'is_report', 'state', 'clinical_speciality',
        'clinical_significance', 'modeless_name', 'sequencing_strategy', 'group_special_test', 'member_add_price', 'analytic_strategy',
        'execute_kind', 'analytic_variation_type', 'sample_type_desc', 'sample_transport', 'free_verification_num', 'point_variation_method',
        'point_variation_price', 'cnv_variation_method', 'cnv_variation_price', 'report_period', 'ngs_period', 'product_attribute',
        'remark', 'monitor_param', 'morepcr_primer', 'capture_chip', 'sequencing_depth', 'single_carry_code', 'single_carry_name',
        'library_type', 'method', 'lci_index', 'si_index', 'insert_size', 'target_yield', 'qc_requirements', 'sequence_platform',
        'sequence_type', 'sequence_length', 'client_index', 'phix', 'delivery_method', 'data_analysis', 'analysis_details',
        'flux', 'discount', 'product_fee', 'way', 'created_by', 'updated_by', 'data_scope'
    ];
    public $sorters = [];
    public $params = [
        'parent_id' , 'code', 'test_method', 'state', 'is_package', 'remark', 'product_fee', 'report_period', 'product_attribute'
    ];

    public function createdBy()
    {
        return $this->belongsTo('App\Models\Account\User', 'created_by');
    }

    public function updatedBy()
    {
        return $this->belongsTo('App\Models\Account\User', 'updated_by');
    }

    public function parent()
    {
        return $this->belongsTo('App\Models\Product\Product', 'parent_id');
    }

    public function testMethod()
    {
        return $this->belongsTo('App\Models\Basic\DictionaryMember', 'test_method', 'code');
    }

    public function productAttribute()
    {
        return $this->belongsTo('App\Models\Basic\DictionaryMember', 'product_attribute', 'code');
    }

    public function sequencePlatform()
    {
        return $this->belongsTo('App\Models\Basic\DictionaryMember', 'sequence_platform', 'code');
    }

    public function sequenceType()
    {
        return $this->belongsTo('App\Models\Basic\DictionaryMember', 'sequence_type', 'code');
    }

    public function way()
    {
        return $this->belongsTo('App\Models\Basic\DictionaryMember', 'way', 'code');
    }

    /**
     * 添加产品
     * @param $data
     * @return int
     */
    public function addProduct($data)
    {
        //检测方法是否存在
        if (isset($data['test_method'])) {
            $method = DictionaryMember::whereHas('dictionary', function ($dictionary) {
                $dictionary->where('code', 'test');
            })->where('code', $data['test_method'])->count();
            if ($method < 1) {
                return null;
            }
        }

        //项目属性是否存在
        if (isset($data['product_attribute'])) {
            $attribute = DictionaryMember::whereHas('dictionary', function ($dictionary) {
                $dictionary->where('code', 'productAttribute');
            })->where('code', $data['product_attribute'])->count();
            if ($attribute < 1) {
                return Code::INSIDE_ERROR;
            }
        }

        //测序平台是否存在
        if (isset($data['sequence_platform'])) {
            $platform = DictionaryMember::whereHas('dictionary', function ($dictionary) {
                $dictionary->where('code', 'sequencePlatform');
            })->where('code', $data['sequence_platform'])->count();
            if ($platform < 1) {
                return Code::INSIDE_ERROR_1;
            }
        }

        //测序类型是否存在
        if (isset($data['sequence_type'])) {
            $type = DictionaryMember::whereHas('dictionary', function ($dictionary) {
                $dictionary->where('code', 'sequenceType');
            })->where('code', $data['sequence_type'])->count();
            if ($type < 1) {
                return Code::INSIDE_ERROR_1;
            }
        }

        //结款方式是否存在  todo:先按照收费方式，如后续需求变动 需更改结款方式-判断
        if (isset($data['way'])) {
            $way = DictionaryMember::whereHas('dictionary', function ($dictionary) {
                $dictionary->where('code', 'sflx');
            })->where('code', $data['way'])->count();
            if ($way) {
                return Code::INSIDE_ERROR_2;
            }
        }

        $userId = Auth::id();
        $data['created_by'] = $userId;
        $data['updated_by'] = $userId;
        $data['data_scope'] = $this->getDataScope();

        return $this->create($data);
    }

    /**
     * 编辑产品
     * @param $data
     * @param $id
     * @return int|null
     */
    public function editProduct($data, $id)
    {
        $model = $this->find($id);

        if (!$model) {
            return null;
        }

        //父级不能为本身
        if (isset($data['parent_id']) == $id) {
            return null;
        }

        //获取其子集
        if (isset($data['parent_id'])) {
            //判断是否为其子集
            $child = $this->where('parent_id', $id)->get(['parent_id', 'id'])->toArray();
            if (count($child) > 0) {
                $childArr = $this->_getAllChild($child, $id);
                $childrenIds = array_column($childArr, 'id');
                if (in_array($data['parent_id'], $childrenIds)) {
                    return null;
                }
            }
        }

        //检测方法是否存在
        if (isset($data['test_method'])) {
            $method = DictionaryMember::whereHas('dictionary', function ($dictionary) {
                $dictionary->where('code', 'test');
            })->where('code', $data['test_method'])->count();
            if ($method < 1) {
                return Code::INSIDE_ERROR;
            }
        }

        //项目属性是否存在
        if (isset($data['product_attribute'])) {
            $attribute = DictionaryMember::whereHas('dictionary', function ($dictionary) {
                $dictionary->where('code', 'productAttribute');
            })->where('code', $data['product_attribute'])->count();
            if ($attribute < 1) {
                return Code::INSIDE_ERROR_1;
            }
        }

        //测序平台是否存在
        if (isset($data['sequence_platform'])) {
            $platform = DictionaryMember::whereHas('dictionary', function ($dictionary) {
                $dictionary->where('code', 'sequencePlatform');
            })->where('code', $data['sequence_platform'])->count();
            if ($platform < 1) {
                return Code::INSIDE_ERROR_2;
            }
        }

        //测序类型是否存在
        if (isset($data['sequence_type'])) {
            $type = DictionaryMember::whereHas('dictionary', function ($dictionary) {
                $dictionary->where('code', 'sequenceType');
            })->where('code', $data['sequence_type'])->count();
            if ($type < 1) {
                return Code::INSIDE_ERROR_2;
            }
        }

        //结款方式是否存在  todo:先按照收费方式，如后续需求变动 需更改结款方式-判断
        if (isset($data['way'])) {
            $way = DictionaryMember::whereHas('dictionary', function ($dictionary) {
                $dictionary->where('code', 'sflx');
            })->where('code', $data['way'])->count();
            if ($way) {
                return Code::INSIDE_ERROR_3;
            }
        }

        $data['updated_by'] = Auth::id();
        return $model->updateOrCreate(['id' => $id], $data);
    }

    /**
     * 获取产品列表
     * @param $limit
     * @param $sorter
     * @param $search
     * @param $defaultSorter
     * @return mixed
     */
    public function getProductList($limit, $sorter, $search, $defaultSorter)
    {
        $perPage = $limit > 0 ? $limit : $this->limit;
        if ($defaultSorter == 'desc') {
            $model = $this->orderBy('created_at', $defaultSorter);
        } else {
            $model = $this->orderBy($sorter[0], $sorter[1]);
        }

        $model->select(['id', 'parent_id', 'title', 'code', 'test_method', 'price', 'is_urgent', 'is_package', 'is_genetic_disease', 'is_genetic_diagnosis',
            'is_family', 'is_contain_family', 'is_more_monitor', 'is_alone_order', 'is_report', 'state', 'clinical_speciality',
            'clinical_significance', 'modeless_name', 'sequencing_strategy', 'group_special_test', 'member_add_price', 'analytic_strategy',
            'execute_kind', 'analytic_variation_type', 'sample_type_desc', 'sample_transport', 'free_verification_num', 'point_variation_method',
            'point_variation_price', 'cnv_variation_method', 'cnv_variation_price', 'report_period', 'ngs_period', 'product_attribute',
            'remark', 'monitor_param', 'morepcr_primer', 'capture_chip', 'sequencing_depth', 'single_carry_code', 'single_carry_name',
            'library_type', 'method', 'lci_index', 'si_index', 'insert_size', 'target_yield', 'qc_requirements', 'sequence_platform',
            'sequence_type', 'sequence_length', 'client_index', 'phix', 'delivery_method', 'data_analysis', 'analysis_details',
            'flux', 'discount', 'product_fee', 'way', 'created_by', 'updated_by', 'created_at', 'updated_at']);

        foreach ($search as $key =>$value) {
            switch ($key) {
                case 'code':
                case 'report_period':
                case 'product_fee':
                case 'remark':
                    $model->where($key, 'like', '%' . $value . '%');
                    break;
                case 'state':
                    $state = explode(',', $value);
                    $model->whereIn('state', $state);
                    break;
                case 'is_package':
                    $isPackage = explode(',', $value);
                    $model->whereIn('is_package', $isPackage);
                    break;
                case 'test_method':
                    $model->whereHas('testMethod', function($test) use($value) {
                       $test->where('code', $value);
                    });
                    break;
                case 'product_attribute':
                    $model->whereHas('productAttribute', function($product) use($value) {
                        $product->where('code', $value);
                    });
                    break;
                case 'parent':
                    $model->whereHas('parent', function($parent) use($value) {
                        $parent->where('code', $value);
                    });
                    break;
            }
        }

        $model->with([
            'testMethod:code,title',
            'productAttribute:code,title',
            'parent:id,title',
            'sequencePlatform:code,title',
            'sequenceType:code,title',
            'way:code,title',
            'createdBy:id,username',
            'updatedBy:id,username'
        ]);

        return $model->paginate($perPage)->toArray();
    }

    public function getProductTree()
    {
        $data = $this->where('state', 1)->all(['id', 'title', 'parent_id', 'code'])->toArray();

        return $this->_setTree($data);
    }

    public function getProduct()
    {

    }

    public function getProductPackageAll()
    {

    }

    //获取库位子集
    public function _getAllChild($data, $id)
    {
        $arr = [];
        foreach ($data as $v) {
            if ($v['parent_id'] == $id) {
                $child['id'] = $v['id'];
                $arr[] = $child;
                $arr = array_merge($arr, $this->_getAllChild($data, $v['id']));
            }
        }
        return $arr;
    }

    //获取树状结构
    /**
     * 生成树状结构数据
     * @param $arr
     * @return array
     */
    public function _setTree($arr)
    {
        //构造数据
        $items = [];
        foreach ($arr as $v) {
            $items[$v['id']] = $v;
        }

        //遍历数据 生成树状结构
        $tree = [];
        foreach ($items as $key => $value) {
            if (isset($items[$value['parent_id']])) {
                $items[$value['parent_id']]['children'][] = &$items[$key];
            } else {
                $tree[] = &$items[$key];
            }
        }

        return $tree;
    }

}
